﻿#region Copyright Notice
// 
// 
//  
//  Copyright (c) 2009-2011 Anindya Chatterjee
//  
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at
//  
//      http://www.apache.org/licenses/LICENSE-2.0
//  
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.
// 
// 
#endregion
using System;
using System.Diagnostics;
using System.Threading;

namespace AbstractClass.NPerf.Framework
{
    /// <summary>
    /// Provides a set of static methods to extract various performance data.
    /// </summary>
    public static class The
    {
        /// <summary>
        /// Returns the memory usage of <paramref name="action"/> in MB.
        /// </summary>
        /// <param name="action">The action whose memory usage is to obtain when it executes.</param>
        public static double MemoryUsageOf(Action action)
        {
            var memMonitor = new MemoryMonitor();

            GC.Collect();
            GC.WaitForPendingFinalizers();
            GC.Collect();

            memMonitor.Start();
            action.Invoke();
            memMonitor.Stop();

            double memUsed = (double) memMonitor.Usage / (1024 * 1024);
            return memUsed;
        }

        /// <summary>
        /// Returns the cpu usage of <paramref name="action"/> in %.
        /// </summary>
        /// <param name="action">The action whose cpu usage is to obtain when it executes.</param>
        public static long CPUUsageOf(Action action)
        {
            Process process = Process.GetCurrentProcess();
            var cpuMonitor = new CPUMonitor();
            double counterSample = 0;
            bool cpuShortTime = true;
            cpuMonitor.GetCPUUsage(process);
            Thread.Sleep(300);

            var t = new Thread(new ThreadStart(delegate
                                                   {
                                                       try
                                                       {
                                                           while (true)
                                                           {
                                                               counterSample = (counterSample +
                                                                                cpuMonitor.GetCPUUsage(process)) / 2;
                                                               cpuShortTime = false;
                                                               Thread.Sleep(300);
                                                           }
                                                       }
                                                           // ReSharper disable EmptyGeneralCatchClause
                                                       catch (Exception)
                                                           // ReSharper restore EmptyGeneralCatchClause
                                                       {
                                                       }
                                                   }));

            t.Start();
            action.Invoke();
            t.Abort();

            if (!cpuShortTime)
            {
                return (long) counterSample;
            }
            throw new AssertionException(LanguageResource.ExecutionTooShort);
        }

        /// <summary>
        /// Returns the duration time of <paramref name="action"/> in milliseconds.
        /// </summary>
        /// <param name="action">The action whose duration is to obtain when it executes.</param>
        public static double DurationOf(Action action)
        {
            double duration = GetDuration(action);
            return duration;
        }

        /// <summary>
        /// Returns the hit-count of <paramref name="action"/> in number/min.
        /// </summary>
        /// <param name="action">The action whose hit-count is to obtain when it executes.</param>
        public static int HitCountOf(Action action)
        {
            double duration = GetDuration(action);
            var hitcount = (int) (60000.0 / duration);
            return hitcount;
        }

        private static double GetDuration(Action action)
        {
            double duration = TimeMonitor.Value;
            action.Invoke();
            duration = (TimeMonitor.Value - duration) / TimeMonitor.Frequency;
            return duration * 1000;
        }
    }
}